from expression import expression
from jsobject import *
from endvals import *
import sys


class plus(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env)

		if(	not( 		
								(
									type(lval) == type(0) or
						  			type(lval) == type(0.0)
						  		) 
						  and 
						  		(
						  			type(rval) == type(0) or 
						  			type(rval) == type(0.0)
						  		)
						 ) 
			and 
				 not 	(
				 			isinstance(lval, stringval) and 
				 			isinstance(rval, stringval)
				 			)
			):
			print "Error: + requires <int> or <float> found"

		return lval + rval

class minus(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: - requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval - rval

class mult(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: * requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval * rval

class div(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: / requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval / rval

class lessThan(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: < requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval < rval

class greatThan(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: > requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval > rval

class lessEq(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: <= requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval <= rval

class greatEq(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if(not((type(lval) == type(0) or type(lval) == type(0.0)) and (type(rval) == type(0) or type(rval) == type(0.0)))):
			print "Error: >= requires <int> or <float> found " + type(lval) + " " + type(rval) + "\n"
		return lval >= rval

class and_(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if((type(lval) != type(1==1)) or (type(rval) != type(1==1))):
			print "Error: and_ requires <bool> found " + type(lval) + " " + type(rval) + "\n"
		return lval and rval

class or_(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval.evaluate(env) 
		rval = self.rval.evaluate(env) 
		if((type(lval) != type(1==1)) or (type(rval) != type(1==1))):
			print "Error: or_ requires <bool> found " + type(lval) + " " + type(rval) + "\n"
		return lval or rval

class not_(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env) 
		if(type(val) != type(1==1)):
			print "Error: not_ requires <bool> found " + type(val) + "\n"
		return not val

class strlen(expression):
	def __init__(self,strg):
		self.strg = strg
	def evaluate(self, env):
		strg = self.strg.evaluate(env).getString() 
		if(type(strg) != type("")):
			print "Error: strlen requires <str> found " + type(strg) + "\n"
		return len(strg)

class substr(expression):
	def __init__(self,strg,s,e):
		self.strg = strg
		self.s = s
		self.e = e
	def evaluate(self, env):
		strg = self.strg.evaluate(env).getString() 
		s = self.s.evaluate(env)
		e = self.e.evaluate(env)
		if(type(strg) != type("")):
			print "Error: substr requires <str> found " + type(strg) + "\n"
		if(not((type(s) == type(0)) and (type(e) == type(0) ))):
			print "Error: start and end requires <int> found " + type(s) + " " + type(e) + "\n"
		return stringval(strg[s:e])

class strEq(expression):
	def __init__(self,strg1,strg2):
		self.strg1 = strg1
		self.strg2 = strg2
	def evaluate(self, env):
		strg1 = self.strg1.evaluate(env).getString() 
		strg2 = self.strg2.evaluate(env).getString() 
		if((type(strg1) != type("")) or (type(strg2) != type(""))):
			print "Error: strEq requires <str> and <str> found " + type(strg1) + " " + type(strg2) + "\n"
		return strg1 == strg2

class strLess(expression):
	def __init__(self,strg1,strg2):
		self.strg1 = strg1
		self.strg2 = strg2
	def evaluate(self, env):
		strg1 = self.strg1.evaluate(env).getString()  
		strg2 = self.strg2.evaluate(env).getString()  
		if((type(strg1) != type("")) or (type(strg2) != type(""))):
			print "Error: strLess requires <str> and <str> found " + type(strg1) + " " + type(strg2) + "\n"
		return strg1 < strg2


class equals(expression):
	def __init__(self,lval,rval):
		self.lval = lval
		self.rval = rval
	def evaluate(self, env):
		lval = self.lval
		rval = self.rval
		#print "Equals: lval:", lval, " rval:", rval, "\n"
		if(not isinstance(self.lval,jsobject)):			
			lval = self.lval.evaluate(env) 
			#print "lval evaluated: ", lval, "\n"
		if(not isinstance(self.rval,jsobject)):
			rval = self.rval.evaluate(env)
			#print "rval evaluated: ", rval, "\n"
		if(isinstance(lval,jsobject) == isinstance(rval,jsobject)):
			#print "lval and rval are objects, id's are: ", id(lval), ", ",id(rval), "\n"
			return id(lval) == id(rval)
		
		if((lval == rval)):
			return True
		return False

class intQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (type(val) == type(0))

class boolQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (type(val) == type(1==1))

class floatQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (type(val) == type(0.0))

class voidQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (type(val) == type(void()))

class stringQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return (isinstance(val,stringval))

class instanceof(expression):
	def __init__(self,obj,val):
		self.val = val
		self.obj = obj
	def evaluate(self, env):
		obj = self.obj.evaluate(env)
		if(not isinstance(obj,jsobject)):
			return False
		else:
			try:
				newobj = obj.access('constructor')
				val = self.val.evaluate(env)
				return newobj == val
			except VarNotFoundExcpt:
				return False

class closureQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		return isinstance(self.val,closure)

class plainQ(expression):
	def __init__(self,val):
		self.val = val
	def evaluate(self, env):
		val = self.val.evaluate(env)
		return isinstance(val,jsobject) and not isinstance(val,closure) and not isinstance(val,stringval)

class printOut(expression):
	def __init__(self,strg):
		self.strg = strg
	def evaluate(self, env):
		print self.strg.evaluate(env),
		sys.stdout.flush()

class readLine(expression):
	def evaluate(self, env):
		strg = raw_input()
		return stringval(str(strg) + "\n")






